package queue

import (
	"context"
	"fmt"
	"sweetsunnyflower/pkg/config"
	"sweetsunnyflower/pkg/logger"
	"sync"
	"time"

	"github.com/hibiken/asynq"
)

var once sync.Once

type Q struct {
	client *asynq.Client
	server *asynq.Server
	mux    *asynq.ServeMux
}

var Queue *Q

func NewQueue() *Q {

	once.Do(func() {
		// 初始化队列
		Queue = &Q{
			client: getClient(),
			server: getServer(),
			mux:    asynq.NewServeMux(),
		}
	})

	return Queue

}

func getClient() *asynq.Client {

	client := asynq.NewClient(asynq.RedisClientOpt{Addr: fmt.Sprintf("%v:%v", config.GetString("redis.host"), config.GetString("redis.port"))})

	return client
}

func getServer() *asynq.Server {
	server := asynq.NewServer(
		asynq.RedisClientOpt{Addr: fmt.Sprintf("%v:%v", config.GetString("redis.host"), config.GetString("redis.port"))},
		asynq.Config{
			// Specify how many concurrent workers to use
			Concurrency: 10,
			// Optionally specify multiple queues with different priority.
			Queues: map[string]int{
				"critical": 6,
				"default":  3,
				"low":      1,
			},
			// See the godoc for other configuration options
		},
	)
	return server
}

func (q *Q) Run(task *asynq.Task, retry int, dealy time.Duration) {
	info, err := q.client.Enqueue(task, asynq.MaxRetry(retry), asynq.ProcessIn(dealy))
	if err != nil {
		logger.ErrorJSON("queue", "run", err)
	} else {
		logger.InfoJSON("queue", "run", info)
	}
}

func (q *Q) Register(name string, handler func(context.Context, *asynq.Task) error) {
	q.mux.HandleFunc(name, handler)
}

func (q *Q) Start() {
	err := q.server.Run(q.mux)
	if err != nil {
		logger.ErrorJSON("queue", "start", err)
	}
}
